﻿static char *tapp_id = 	"@(#)Copyright (C) gaoguangtao   tapp.cpp	Ver2.06";

//应用程序类源文件
/* ========================================================================
	Project  Name			: Win32 Lightweight  Class Library Test
	Module Name				: Application Frame Class
	Create					: 2008-02-20(Sat)
    Update					: 2008-02-14(Wed)
	Copyright				: gaoguangtao
	Reference				: 
	======================================================================== */

#include "tlib.h"

TWin**		TApp::wndArray		= NULL;
int			TApp::wndCnt		= 0;
TWin*		TApp::preWnd		= NULL;
HINSTANCE	TApp::hI			= NULL; //应用程序实例
char*		TApp::defaultClass	= "tapp";

HINSTANCE LoadCtl3d(void);

TApp::TApp(HINSTANCE _hI, LPSTR _cmdLine, int _nCmdShow)
{
	TApp::hI            = _hI;
	
	this->cmdLine       = _cmdLine;
	this->nCmdShow      = _nCmdShow;
	this->mainWnd       = NULL;

	//::CoInitializeEx(NULL, COINIT_SPEED_OVER_MEMORY); //主要是告诉windows以 什么 方式为程序创建COM对象
	
	this->hCtl3d = LoadCtl3d(); //

	//InitCommonControls() is required on Windows XP if an application manifest specifies use of ComCtl32.dll version 6 
	//or later to enable visual styles.  Otherwise, any window creation will fail.
	::InitCommonControls();
}

TApp::~TApp()
{
	delete mainWnd;

	if (hCtl3d)
	{
		::FreeLibrary(hCtl3d);
	}

	::CoUninitialize();
}

int TApp::Run(void) //virtual
{
	MSG msg;

	InitApp();  //virtual， 注册了TAPP
	InitWindow(); //virtual

	BOOL bRet;
	//函数返回值可能是0，大于0，或者等于-1。
	//1) 如果成功获取一条非WM_QUIT消息时，就返回大于0的值；
	//2) 如果获取WM_QUIT消息时，就返回值0值。
	//3) 如果出错就返回-1的值
	while (bRet = ::GetMessage(&msg, NULL, 0, 0)) //GetMessage同步函数
	{
		if (bRet == -1)//防止发生错误时造成死循环
		{
			//TODO: handle the error and possibly exit
			return -1;
		}
		else
		{
			if (TApp::PreProcMsg(&msg)) //TAPP 预处理消息
			{
				continue;
			}

			::TranslateMessage(&msg);
			::DispatchMessage(&msg);
		}
	}

	return msg.wParam;
}

BOOL TApp::PreProcMsg(MSG *msg)	// for TranslateAccel & IsDialogMessage
{
	for (HWND hWnd = msg->hwnd; hWnd != NULL; hWnd = ::GetParent(hWnd))
	{
		TWin *win = TApp::SearchWnd(hWnd);

		if (win != NULL)
		{
			return win->PreProcMsg(msg);
		}
	}

	return FALSE;
}

LRESULT CALLBACK TApp::WinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	TWin *win = TApp::SearchWnd(hWnd);

	if (win)
	{
		return win->WinProc(uMsg, wParam, lParam);
	}

	win = TApp::preWnd;
	if (win != NULL)
	{
		TApp::preWnd = NULL;
		AddWinByWnd(win, hWnd);

		return win->WinProc(uMsg, wParam, lParam);
	}

	return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

void TApp::AddWin(TWin *win)
{
	TApp::preWnd = win;
}

void TApp::AddWinByWnd(TWin *win, HWND hWnd)
{
	win->hWnd = hWnd;

	AddWinSub(win);
}

void TApp::AddWinSub(TWin *win)
{
	if (TApp::SearchWnd(win->hWnd) != NULL)
	{
		return;
	}

#define BIG_ALLOC	100

	TWin **_wndArray = TApp::wndArray;

	if ((TApp::wndCnt % BIG_ALLOC) == 0)
	{
		_wndArray = (TWin **)realloc(TApp::wndArray, sizeof(TWin *) * (TApp::wndCnt + BIG_ALLOC));
	}

	if (_wndArray == NULL)
	{
		return;
	}

	TApp::wndArray = _wndArray;
	TApp::wndArray[TApp::wndCnt] = win;
	TApp::wndCnt++;

	return;
}

void TApp::DelWin(TWin *win)
{
	int		index;

	if (SearchWndIndex(win, &index) != TRUE)
	{
		if (preWnd == win)
			preWnd = NULL;
		return;
	}

	memmove(wndArray + index, wndArray + index +1, sizeof(TWin *) * (--wndCnt - index));
//	wndArray = (TWin **)realloc(wndArray, sizeof(TWin *) * wndCnt);
}

BOOL TApp::InitApp(void)	// reference kwc
{
	WNDCLASS wc;

	memset(&wc, 0, sizeof(wc)); //把wc的内存空间全部初始化为零

	wc.style			= (CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW | CS_DBLCLKS);
	wc.lpfnWndProc		= TApp::WinProc;
	wc.cbClsExtra 		= 0;
	wc.cbWndExtra		= 0;
	wc.hInstance		= TApp::hI;
	wc.hIcon			= NULL;
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground	= NULL;
	wc.lpszMenuName		= NULL;
	wc.lpszClassName	= defaultClass;

	if (::FindWindow(defaultClass, NULL) == NULL)
	{
		if (::RegisterClass(&wc) == 0)
		{
			return FALSE;
		}
	}

	return	TRUE;
}

TWin* TApp::SearchWnd(HWND hWnd)
{
	for (int cnt = 0; cnt < TApp::wndCnt; cnt++)
	{
		if (TApp::wndArray[cnt]->hWnd == hWnd)
		{
			return TApp::wndArray[cnt];
		}
	}

	return	NULL;
}

BOOL TApp::SearchWndIndex(TWin *win, int *index)
{
	for (*index=0; *index < wndCnt; (*index)++)
		if (wndArray[*index] == win)
			return	TRUE;

	return	FALSE;
}

HINSTANCE LoadCtl3d(void)
{
	if (IsNewShell()) //作用？？？？？WindowsXP系统及其以上版本直接退出
	{
		return NULL;
	}

	HINSTANCE hCtl3d;
	BOOL (WINAPI *Ctl3dRegister)(HANDLE);
	BOOL (WINAPI *Ctl3dAutoSubclass)(HANDLE);

	hCtl3d = ::LoadLibrary("ctl3d32.dll");

	Ctl3dRegister = (BOOL (WINAPI *)(HANDLE))::GetProcAddress(hCtl3d, "Ctl3dRegister");
	Ctl3dAutoSubclass = (BOOL (WINAPI *)(HANDLE))::GetProcAddress(hCtl3d, "Ctl3dAutoSubclass");

	if (Ctl3dRegister && Ctl3dAutoSubclass)
	{
		Ctl3dRegister(TApp::hI);
		Ctl3dAutoSubclass(TApp::hI);
	}

	return hCtl3d;
}